import * as vscode from 'vscode';
import { LanguageClient, LanguageClientOptions, ServerOptions } from 'vscode-languageclient/node';
import { ServerManager } from './serverManager';
import { debug } from './logger';
import WebSocket from 'ws';
import { WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc/cjs';
import { Buffer } from 'buffer';

export class RemoteLspClient {
    private static instance: RemoteLspClient;
    private client: LanguageClient | null = null;
    private isStarted = false;

    private constructor() {
        // 监听服务器变化
        const serverManager = ServerManager.getInstance();
        serverManager.onServerChanged(this.onServerChanged.bind(this));
    }

    public static getInstance(): RemoteLspClient {
        if (!RemoteLspClient.instance) {
            RemoteLspClient.instance = new RemoteLspClient();
        }
        return RemoteLspClient.instance;
    }

    // 服务器变化处理
    private async onServerChanged(serverId: string | null): Promise<void> {
        await this.stop();
        
        if (serverId) {
            await this.start();
        }
    }

    // 启动 LSP 客户端
    async start(): Promise<void> {
        try {
            const serverManager = ServerManager.getInstance();
            const currentServer = serverManager.getCurrentServer();
            
            if (!currentServer) {
                vscode.window.showWarningMessage('请先选择一个 Magic API 服务器');
                return;
            }

            const lspUrl = await serverManager.getLspUrl(currentServer.id);
            if (!lspUrl) {
                vscode.window.showErrorMessage('无法获取 LSP 服务器地址');
                return;
            }
            debug(`RemoteLspClient connecting to LSP: ${lspUrl}`);
            // 使用 WebSocket 建立 JSON-RPC 连接
            const serverOptions: ServerOptions = () => {
                return new Promise((resolve, reject) => {
                    const client = serverManager.getCurrentClient();
                    const headers = client?.getAuthHeaders() || {};
                    // Advertise LSP4J websocket subprotocols for better compatibility
                    const ws = new WebSocket(lspUrl, { perMessageDeflate: false, headers });
                    ws.on('open', () => {
                        const negotiatedProtocol: string = (ws as any).protocol || '';
                        const isBase64 = negotiatedProtocol.endsWith('.base64');
                        debug(`RemoteLspClient WS connected. Negotiated protocol: ${negotiatedProtocol || 'none'}`);

                        const socket = {
                            send: (content: string) => {
                                try {
                                    const payload = isBase64
                                        ? Buffer.from(content, 'utf8').toString('base64')
                                        : content;
                                    ws.send(payload);
                                } catch (e) {
                                    // Fallback to plain send
                                    ws.send(content);
                                }
                            },
                            onMessage: (cb: (data: any) => void) => ws.on('message', (data: any) => {
                                const raw = typeof data === 'string' ? data : data?.toString?.() ?? '';
                                const decoded = isBase64 && raw
                                    ? (() => { try { return Buffer.from(raw, 'base64').toString('utf8'); } catch { return raw; } })()
                                    : raw;
                                cb(decoded);
                            }),
                            onError: (cb: (reason: any) => void) => ws.on('error', (err: any) => cb(err)),
                            onClose: (cb: (code: number, reason: string) => void) => ws.on('close', (code: number, reason: any) => cb(code, typeof reason === 'string' ? reason : reason?.toString?.() ?? '')),
                            dispose: () => ws.close()
                        };
                        const reader = new WebSocketMessageReader(socket);
                        const writer = new WebSocketMessageWriter(socket);
                        resolve({ reader, writer });
                    });
                    ws.on('error', (err) => reject(err));
                });
            };

            // 客户端选项
            const clientOptions: LanguageClientOptions = {
                documentSelector: [
                    { scheme: 'file', language: 'magic-script' },
                    { scheme: 'magic-api', language: 'magic-script' }
                ],
                synchronize: {
                    fileEvents: vscode.workspace.createFileSystemWatcher('**/*.ms')
                },
                middleware: {
                    async provideDocumentSymbols(document, token, next) {
                        try {
                            const result = await next(document, token);
                            if (!result) return result;
                            const arr: any[] = Array.isArray(result) ? (result as any[]) : [];
                            // Filter out items with falsy or empty names to avoid extension host errors
                            const filtered = arr.filter((s: any) => {
                                const name = s?.name;
                                return typeof name === 'string' && name.trim().length > 0;
                            });
                            return filtered;
                        } catch (e) {
                            // If conversion throws (e.g., due to invalid names), avoid crashing outline by returning empty list
                            debug(`provideDocumentSymbols failed; returning empty list: ${e}`);
                            return [];
                        }
                    }
                }
            };

            // 创建语言客户端
            this.client = new LanguageClient(
                'magic-api-lsp',
                'Magic API Language Server',
                serverOptions,
                clientOptions
            );

            // 启动客户端
            await this.client.start();
            this.isStarted = true;
            
            vscode.window.showInformationMessage('Magic API 语言服务器已启动');
            
        } catch (error) {
            vscode.window.showErrorMessage(`启动 LSP 客户端失败: ${error}`);
        }
    }

    // 停止 LSP 客户端
    public async stop(): Promise<void> {
        if (this.client && this.isStarted) {
            try {
                await this.client.stop();
                vscode.window.showInformationMessage('Magic API LSP 已断开连接');
            } catch (error) {
                console.error('停止 LSP 客户端失败:', error);
            }
        }

        this.client = null;
        this.isStarted = false;
    }

    // 重启 LSP 客户端
    public async restart(): Promise<void> {
        await this.stop();
        await this.start();
    }

    // 获取客户端状态
    public isRunning(): boolean {
        return this.isStarted && this.client !== null;
    }

    // 获取客户端实例
    public getClient(): LanguageClient | null {
        return this.client;
    }

    // 发送自定义请求
    public async sendRequest<P, R>(method: string, params?: P): Promise<R | null> {
        if (!this.client || !this.isStarted) {
            return null;
        }

        try {
            return await this.client.sendRequest(method, params);
        } catch (error) {
            console.error(`发送请求 ${method} 失败:`, error);
            return null;
        }
    }

    // 发送自定义通知
    public async sendNotification<P>(method: string, params?: P): Promise<void> {
        if (!this.client || !this.isStarted) {
            return;
        }

        try {
            await this.client.sendNotification(method, params);
        } catch (error) {
            console.error(`发送通知 ${method} 失败:`, error);
        }
    }

    // 销毁
    public async dispose(): Promise<void> {
        await this.stop();
    }
}